home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
assemblr
/
library
/
sampler0
/
whereis.asm
< prev
next >
Wrap
Assembly Source File
|
1987-05-05
|
12KB
|
518 lines
name whereis
title 'WHEREIS -- find file'
page 55,132
;
; WHEREIS -- find file in directory structure
; by John Scotia, first published in Softalk/IBM
; modified by Ray Duncan
;
lf equ 0ah ;ASCII line feed
cr equ 0dh ;ASCII carriage return
ff equ 0ch ;ASCII form feed
tab equ 09h
eom equ '$' ;end of message flag
;
;Program Segment Prefix
default_fcb equ 05ch
command equ 80h
default_dta equ 080h
;
;
; This is the format for the DOS Data Transfer Area used when DOS 2.0
; searches for a file match in directories.
DTA STRUC
RESERVED DB 21 DUP (?)
ATTRIBUTE DB 0
TIME DW 0
DATE DW 0
SIZE DD 0
NAME_FOUND DB 13 DUP (?)
DTA ENDS
cseg segment para public 'CODE'
assume cs:cseg,ds:data,es:data,ss:stack
page
; This is the main program that sets up the initial conditions for
; SDIR which, in turn, does a recursive search.
;
; Reads: PATH_NAME
; Writes: FILE_NAME
; Calls: SDIR
whereis proc far
push ds ;save final return
xor ax,ax
push ax
mov bp,sp ;save pointer to final return
; in case we want to exit
; inside recursive routine
mov ax,data ;make data segment addressable
mov es,ax ;via ES
call infile ;get name of search target
mov ax,data ;make data segment addressable
mov ds,ax ;via DS
jnc whereis1 ;jump if filename was ok
;filename was missing,
mov dx,offset msg1 ;print error message and exit
mov ah,9
int 21h
ret
whereis1:
mov ah,30h ;check DOS version
int 21h
cmp al,2
jae whereis2 ;proceed, DOS 2.0 or greater
mov dx,offset msg3 ;DOS 1.1 --- print message
mov ah,9 ;and exit
int 21h
ret
whereis2:
MOV DI,OFFSET PATH_NAME
XOR AL,AL ;Search for the zero at the end
CLD ; of PATH_NAME
MOV CX,64 ;Max. length of scan for 0
REPNZ SCASB
MOV BX,DI
DEC BX ;DS:BX points to end of PATH_NAME
MOV DX,0 ;Tell SDIR this is first
CALL SDIR ;Now do the recursive search
mov ax,match_count ;were any matches found?
or ax,ax
jz whereis8 ;no,jump
ret ;yes,just exit
whereis8:
mov dx,offset msg2 ;no,print "no match"
mov ah,9
int 21h
ret
;this is a special crash
;exit, which may be taken
;from inside recursed proc.
whereis9:
mov sp,bp
ret
whereis endp
page
; This procedure searches all the files in the current directory
; looking for a match. It also prints the full name for each match.
;
; DS:BX Pointer to end of current path name
; DS:DX Old disk transfer area (DTA)
;
; Reads: Disk Transfer Area (DTA)
; Writes: Disk Transfer Area (DTA)
; Calls: BUILD_NAME, FMATCH, PNAME
; NMATCH, BUILD_STAR_NAME, SSUB
SDIR PROC NEAR
PUSH SI ;Need to restore on exit
PUSH DX
CALL BUILD_NAME ;Build the absolute search name
CALL FMATCH ;See if there is a match here
JC sdir2 ;No match, check subdirectories
CALL PNAME ;Write name of match.
sdir1:
CALL NMATCH ;Find the next match
JC sdir2 ;No match, search sub-directories
CALL PNAME ;Match, write absolute name
JMP sdir1 ;Look for the next matching name
sdir2: ;No match, so try sub-directories.
POP DX ;Restore DTA
PUSH DX
CALL BUILD_STAR_NAME ;Search for all directories
CALL FMATCH ;Get first entry
JC SDIR5 ;There are no entries
MOV SI,DX ;Put address of DTA into SI
TEST [SI].ATTRIBUTE,10H ;Is it a directory entry?
JNZ SDIR4 ;Yes, then search sub-directory
SDIR3:
CALL NMATCH ;No, then find the next match
JC SDIR5 ;There are no more entries
TEST [SI].ATTRIBUTE,10H ;Is this a directory?
JZ SDIR3 ;No, then try again
SDIR4:
CMP [SI].NAME_FOUND,'.' ;Is this a . or .. directory?
JE SDIR3 ;Yes, skip to next directory
CALL SSUB ;Search the sub-directory
PUSH AX ;Now reset the DTA
MOV AH,1AH
INT 21H
POP AX
JMP SDIR3
SDIR5:
POP DX
POP SI
RET
SDIR ENDP
page
; This procedure searches the subdirectory whos name is in the DTA
;
; DS:BX End of the current path name
; DS:[DX].NAME_FOUND Name of subdirectory for search
; Reads: PATH_NAME
; Writes: PATH_NAME
; Calls: SDIR
SSUB PROC NEAR
PUSH DI
PUSH SI
PUSH AX
PUSH BX
CLD ;Set for increment
MOV SI,DX ;Put address of DTA into SI
ADD SI,OFFSET NAME_FOUND ;Set to start of sub-directory name
MOV DI,BX ;DS:DI -- 0 at end of path name
ssub1: ;Copy sub-directory to path name
LODSB ;Copy one character
STOSB
OR AL,AL ;Was it a 0?
JNZ ssub1 ;No, keep copying
MOV BX,DI ;Set BX to end of new path name
STD ;Set flag for decrement
STOSB ;Store a 0 at end of string
MOV AL,'\'
STOSB ;Place '\' at end of path name
CALL SDIR ;Search this new path
POP BX ;Restore the old end-of-path
MOV BYTE PTR [BX],0 ;And store a zero here
POP AX
POP SI
POP DI
RET
SSUB ENDP
page
; This procedure prints the matched name after the path name
;
; DS:DX Pointer to current disk transfer area
;
; Reads: PATH_NAME, NAME_FOUND (in DTA)
; Calls: pasciiz, CRLF
PNAME PROC NEAR
PUSH AX
PUSH DX
MOV DX,OFFSET PATH_NAME
MOV AL,[BX] ;Save character at end of path
MOV BYTE PTR [BX],0 ;Set for end of string
CALL pasciiz
MOV [BX],AL ;Restore character
POP DX ;Recover old pointer
PUSH DX
ADD DX,OFFSET NAME_FOUND
CALL pasciiz
cmp byte ptr switch,'g' ;global switch set?
je pname2 ;yes,keep searching
;no, check if user wants
;to keep looking.
push dx ;save current DTA
mov dx,offset msg4 ;print 'More? '
mov ah,9
int 21h
mov ah,7 ;read console without echo
int 21h
or al,20h ;fold to lower case
cmp al,'y' ;must be y, anything else exits
je pname1
jmp whereis9 ;take crash exit
pname1: mov dl,al ;if Y,echo it
mov ah,2
int 21h
pop dx ;restore pointer to DTA
pname2: CALL CRLF
inc match_count ;count names displayed
POP DX
POP AX
RET
PNAME ENDP
page
; This procedure builds an absolute search name from PATH_NAME
; followed by FILE_NAME.
;
; Reads: FILE_NAME
; Calls: BUILD to build the name
BUILD_NAME PROC NEAR
PUSH SI
MOV SI,OFFSET FILE_NAME
CALL BUILD
POP SI
RET
BUILD_NAME ENDP
BUILD_STAR_NAME PROC NEAR
PUSH SI
MOV SI,OFFSET STAR_NAME
CALL BUILD
POP SI
RET
BUILD_STAR_NAME ENDP
; This procedure appends the string at DS:SI to PATH_NAME in
; PATH_NAME. It knows where the path name ends from knowing how
; long PATH_NAME is.
;
; DS:SI Name of file
; DS:BX End of PATH_NAME
;
; Reads: DS:SI
; Writes: PATH_NAME
BUILD PROC NEAR
PUSH AX
PUSH DI
MOV DI,BX
CLD ;Set direction for increment
build1:
LODSB ;Copy one character of name
STOSB
OR AL,AL ;End of string yet?
JNZ build1 ;No, keep copying
POP DI
POP AX
RET
BUILD ENDP
page
; This procedure finds the first match between the name given by
; DS:DX and the directory entries found in the directory PATH_NAME.
;
; DS:DX Pointer to current disk transfer area
; Returns:
; CF 0 A match was found
; 1 No match found
; AX Error code returned:
; 2 File not found
; 18 No more files
; DS:DX Pointer to new disk transfer area
;
; Reads: PATH_NAME
; Writes: dbuff
FMATCH PROC NEAR
PUSH CX
CMP DX,0 ;First one?
JA ALLOCATE ;No, then allocate space
MOV DX,OFFSET dbuff-TYPE DTA
allocate:
add dx,type dta ;no, then allocate room for new DTA
MOV CX,10H ;Search attribute for files and dirs.
MOV AH,1AH ;Set disk transfer address
INT 21H
PUSH DX ;Need DX for address of search name
MOV DX,OFFSET PATH_NAME
MOV AH,4EH ;Call for "find first match"
INT 21H
POP DX
POP CX
RET ;Return with carry flag info
FMATCH ENDP
page
; Get next match for filename
; (very similar to Get first match routine)
; Returns:
; CF 0 A match was found
; 1 No match found
; AX Error code returned:
; 2 File not found
; 18 No more files
;
; Reads: PATH_NAME
; Writes: dbuff
NMATCH PROC NEAR
PUSH CX
PUSH DX
MOV DX,OFFSET PATH_NAME
MOV CX,10H ;Attribute for files and directories
MOV AH,4FH ;Call for "Find next match"
INT 21H
POP DX
POP CX
RET ;Return with carry flag intact
NMATCH ENDP
page
; Send CRLF sequence to the screen.
CRLF PROC NEAR
PUSH AX
PUSH DX
MOV AH,02
MOV DL,0AH
INT 21H
MOV DL,0DH
INT 21H
POP DX
POP AX
RET
CRLF ENDP
page
; Display ASCIIZ string
; Call with DS:DX = string addr
pasciiz PROC NEAR
PUSH AX
PUSH DX
PUSH SI
CLD ;Set direction for increment
MOV SI,DX ;Set up pointer to string
MOV AH,2
pasciiz1:
LODSB ;Get character
or al,al ;if zero,all done
jz pasciiz2
MOV DL,AL
INT 21H ;Write one character
jmp pasciiz1 ;loop till string exhausted
pasciiz2:
POP SI
POP DX
POP AX
RET
pasciiz ENDP
page
infile proc near ;process name of input file
;DS:SI <- addr command line
mov si,offset command
;ES:DI <- addr filespec buffer
mov di,offset file_name
cld
lodsb ;any command line present?
or al,al ;return error status if not.
jz infile4
infile1: ;scan over leading blanks
lodsb ;to file name
cmp al,cr ;if we hit carriage return
jz infile4 ;filename is missing.
cmp al,20h ;is this a blank?
jz infile1 ;if so keep scanning.
xor ah,ah ;reset "." found flag
;found first char of name
infile2:
cmp al,'\' ;if slash,reset "." flag
jne infile22
xor ah,ah
infile22: ;check if extension specified
cmp al,'.'
jne infile24
inc ah
infile24: ;
stosb ;move last char. to output
;file name buffer.
lodsb ;check next character, found
cmp al,cr ;carriage return yet?
je infile3 ;yes,exit with success code
cmp al,'/' ;or if we hit a switch delimiter
jne infile26
infile25:
lodsb ;get the switch char and save it
or al,20h ;force to lower case
mov byte ptr es:switch,al
jmp infile3 ;then jump to finish up
infile26:
cmp al,20h ;is this a blank?
jne infile2 ;if not keep moving chars.
infile27:
lodsb ;search up to end, in case of switch
cmp al,'/'
je infile25 ;found switch,go save it
cmp al,cr
jne infile27 ;otherwise, fscan until CR found
infile3: ;found end of input name
or ah,ah ;was "." found?
jnz infile35 ;yes,jump
mov al,'.' ;no,force ext to wildcard
stosb
mov al,'*'
stosb
infile35:
xor al,al ;store trailing null byte
stosb ;exit with CY=0 as success flag
clc
ret
infile4: ;exit with carry =1
stc ;for error flag
ret
infile endp
cseg ends
page
data segment para public 'DATA'
STAR_NAME DB '*.*',0
PATH_NAME DB '\',0
DB 80 DUP (0) ;Space for 64 character path name
; and 13 character file name
FILE_NAME DB 13 DUP (0) ;Save room for full DOS file name
msg1 db cr,lf
db 'Missing file name.'
db cr,lf,eom
msg2 db cr,lf
db 'No match found.'
db cr,lf,eom
msg3 db cr,lf
db 'Requires DOS version 2.0 or greater.'
db cr,lf,eom
msg4 db tab,' More (y/n) ? ',eom
match_count dw 0 ;number of filenames matching
;input filespec
switch db 0 ;char following / saved here
dbuff equ $ ;this starts the scratch area
;which will be used as search
;buffers. It is right under
;the stack, which is made very
;large to give it room.
data ends
stack segment para stack 'STACK'
db 32768 dup (?)
stack ends
end whereis